package com.zndroid.gridview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;

import androidx.annotation.NonNull;
import androidx.core.content.res.ResourcesCompat;

import com.zndroid.gridview.inner.widget.GridDragImageViewWrapper;
import com.zndroid.gridview.inner.drag.GridDragFixedFirstAdapter;
import com.zndroid.gridview.inner.drag.GridDragFixedLastAdapter;
import com.zndroid.gridview.inner.drag.OnItemMovedListener;
import com.zndroid.gridview.load.IImageDisplayEngine;
import com.zndroid.gridview.load.ImageLoader;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

/**
 * @author lzy
 */
public abstract class AGridDragAdapter<T extends IImageBean> extends BaseAdapter
        implements OnItemMovedListener, GridDragImageViewWrapper.IDeleteClick
{
    protected List<T> list;
    protected IImageDisplayEngine engine;
    private GridView mGridView;
    /**是否显示删除icon*/
    private boolean showDeleteIcon;
    /**自定义删除icon*/
    private Drawable deleteIcon;
    /**
     * 是否自动过滤“固定桩 FixPile”
     * true: 当达到设置的max值时,自动隐藏固定桩,最终获取到的数据也会进行过滤（默认，用于实现微信发朋友圈效果）
     * false: 固定桩作为有效数据，参与到最大数max计算中,最终获取到的数据不会进行过滤
     *
     * See Also:{@link #getFinalResult()}
     * */
    private boolean autoDismissFixPile = true;

    /**最多展示个数（默认9个）*/
    private int max = 9;

    /**
     * 固定桩（暂时只支持一个，且要么在首位要么在末尾，这也是使用该组件最常用的）
     * See Also:
     * {@link com.zndroid.gridview.inner.drag.GridDragFixedFirstAdapter} or
     * {@link com.zndroid.gridview.inner.drag.GridDragFixedLastAdapter}
     * */
    private T fixedPile;

    private final WeakReference<Context> context;
    private IDataChangedCallBack dataChangedCallBack;

    public AGridDragAdapter(Context context, @NonNull List<T> list) {
        this.list = list;
        this.context = new WeakReference<>(context);
    }

    public void setDataChangedCallBack(IDataChangedCallBack dataChangedCallBack) {
        this.dataChangedCallBack = dataChangedCallBack;
    }

    public void showDeleteIcon(boolean showDeleteIcon) {
        this.showDeleteIcon = showDeleteIcon;
        notifyDataSetChanged();
    }

    public void setAutoDismissFixPile(boolean autoDismissFixPile) {
        this.autoDismissFixPile = autoDismissFixPile;
    }

    public void setDeleteIcon(Drawable deleteIcon) {
        this.deleteIcon = deleteIcon;
    }

    public boolean isAutoDismissFixPile() {
        return autoDismissFixPile;
    }

    public void setMax(int max) {
        this.max = max;
        notifyDataSetChanged();
    }

    public void setFixedPile(T fixedPile) {
        this.fixedPile = fixedPile;
    }

    public T getFixedPile() {
        return fixedPile;
    }

    public int getMax() {
        return max;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public T getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (mGridView == null) {
            mGridView = (GridView) parent;
        }

        GridDragImageViewWrapper imageView;

        if (null == engine) {
            throw new UnsupportedOperationException("image load engine is null, pls impl it at first.");
        }

        if (convertView == null) {
            imageView = new GridDragImageViewWrapper(context.get());
            convertView = imageView;

            int width = ViewGroup.LayoutParams.MATCH_PARENT;
            int height = mGridView.getColumnWidth();

            imageView.setLayoutParams(new ViewGroup.LayoutParams(width, height));
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            if (deleteIcon != null) {
                imageView.setDeleteIcon(deleteIcon);
            }
        } else {
            imageView = (GridDragImageViewWrapper) convertView;
        }

        if (isFixed(position) && list.contains(fixedPile)) {
            //固定桩不显示删除，不显示覆盖图层
            imageView.showDeleteIcon(false);
            imageView.setCoverBitmap(null);
        } else {
            imageView.showDeleteIcon(showDeleteIcon);

            Bitmap bitmap = getCoverBitmap(position);

            if (null != bitmap) {
                imageView.setCoverBitmap(bitmap);
            }
        }

        //listener
        imageView.setDeleteClick(this);
        //image loader
        ImageLoader.getLoader().load(context, imageView, engine, list.get(position), null);

        return convertView;
    }

    private Bitmap getCoverBitmap(int position) {
        int coverResId = list.get(position).supplyCoverResId();
        if (coverResId <= 0) {
            return null;
        }
        try {
            Drawable drawable = ResourcesCompat.getDrawable(context.get().getResources(), coverResId, context.get().getTheme());
            if (drawable instanceof BitmapDrawable) {
                return ((BitmapDrawable) drawable).getBitmap();
            }

        } catch (Exception e) {
            return null;
        }

        return null;
    }

    @Override
    public void onItemDeleteClicked(View view) {
        int index = mGridView.indexOfChild(view);
        //not found
        if (index < 0) {return;}

        int finalPos = index + mGridView.getFirstVisiblePosition();
        list.remove(finalPos);
        notifyDataSetChanged();

        dataHasChanged(list, getFinalResult());
    }

    @Override
    public void onItemMoved(int from, int to) {
        T bean = list.remove(from);
        list.add(to, bean);

        dataHasChanged(list, getFinalResult());
    }

    public List<T> getFinalResult() {
        if (autoDismissFixPile) {
            //防止使用同一个指针引用
            List<T> result = new ArrayList<>();
            result.addAll(list);
            result.remove(fixedPile);
            return result;
        } else {
            return list;
        }
    }

    private void dataHasChanged(List<T> allList, List<T> realityList) {
        if (null != dataChangedCallBack) {
            dataChangedCallBack.onChanged(allList, realityList);
        }
    }

    public interface IDataChangedCallBack {
        /**
         * data has changed
         *
         * @param allList all list contains fixedPile
         * @param realityList final list not contains fixedPile
         * */
        void onChanged(List<? extends IImageBean> allList, List<? extends IImageBean> realityList);
    }

    @Override
    public void notifyDataSetChanged() {
        //数据源控制中枢
        if (null != fixedPile) {
            if (this instanceof GridDragFixedLastAdapter) {
                if (autoDismissFixPile) {
                    //重置有效list
                    list.remove(fixedPile);
                    fixIntercept(false);

                    if (list.size() < max) {
                        list.add(fixedPile);
                    } else {
                        fixIntercept(true);
                    }
                } else {
                    list.remove(fixedPile);
                    list.add(fixedPile);
                }
            } else if (this instanceof GridDragFixedFirstAdapter) {
                if (autoDismissFixPile) {
                    //重置有效list
                    list.remove(fixedPile);
                    if (list.size() < max) {
                        list.add(0, fixedPile);
                    }
                } else {
                    //每次更新先移除固定桩，然后在原来的位置重新加上
                    int index = list.indexOf(fixedPile);
                    list.remove(fixedPile);
                    if (-1 != index) {
                        list.add(index, fixedPile);
                    } else {
                        //初始数据为空时添加固定桩
                        list.add(fixedPile);
                    }
                }
            }
        }

        super.notifyDataSetChanged();
    }

    /**
     * 内部使用，用于拦截固定桩是否有效
     * 用于处理 {@link GridDragFixedLastAdapter} 在 {@link #autoDismissFixPile} 时，
     * 元素个数充满{@link #max}场景下，不能进行长按拖动
     * */
    boolean intercept = false;
    private void fixIntercept(boolean intercept) {
        this.intercept = intercept;
    }

    public boolean isFixIntercept() {
        return intercept;
    }
}
